package com.zhangtai.filter;


import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.zhangtai.exception.DateUtils;
import com.zhangtai.exception.RException;
import com.zhangtai.utils.TokenDecode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: ming
 * @Date: 2020/2/7 0007 下午 1:21
 */
@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private RedisTemplate redisTemplate;




    private static final String AUTHORIZE_TOKEN = "Authorization";
    private static final String SCOPE = "ehr";



//
    private String accessUrl="/api-admin/login,/api-admin/eSign/eSignCallBack,/api-admin/member/getEmployeeById/*,/api-admin/member/getEmployeeByIdAuth,/api-admin/member/saveMainInfo," +
        "/api-admin/member/updateMainInfo,/api-admin/member/deleteMainInfo/*,/api-admin/member/getEducationInfo/*,/api-admin/member/saveEducationInfo," +
        "/api-admin/member/updateEducationInfo,/api-admin/member/deleteEducation/*,/api-admin/member/getInorgInfo/*,/api-admin/member/saveInorgInfo," +
        "/api-admin/member/updateInorgInfo,/api-admin/member/deleteInorg/*,/api-admin/member/saveSociety,/api-admin/member/updateSociety,/api-admin/member/getSociety/*," +
        "/api-admin/member/deleteSociety/*,/api-admin/member/getFamily/*,/api-admin/member/getFamily/*,/api-admin/member/saveFamily,/api-admin/member/updateFamily," +
        "/api-admin/member/deleteFamily/*,/api-admin/oss/upload,/api-admin/job/getNativeplace,/api-admin/loginByUserAndPwd,/api-admin/neusoft/findDictionary";





    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {


        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();


//        String s = request.getRemoteAddress().getAddress().toString();



//        获取当前请求,如果是登录请求则放行
        String path = request.getURI().getPath();
        log.info("请求路径是：{}",path);
        if (isAccess(path)){
            log.info("需要放行的请求路径是：{}",path);

            return chain.filter(exchange);
        }

//如果从请求头获取到token,
//        String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);
        List<String> headers = request.getHeaders().get("Authorization");
        String token = null;
        if (!CollectionUtils.isEmpty(headers)){
            for (String header : headers) {
                if (!StringUtils.isEmpty(header)&&header.contains("Bearer")&&header.length()>8){
                    String bearer = header.replace("Bearer ", "");

                    try {
                        String preDecode = TokenDecode.decode(bearer);
                        Map<String,Object> map = JSON.parseObject(preDecode, Map.class);
                        List<String> scopes= (List<String>) map.get("scope");
                        if (scopes.contains(SCOPE)){

                            token=bearer;
                            String uuid = (String) map.get("uuid");
//        log.info("uuid===========>>>>>>>:{}",uuid);

                            HashMap<String, Object> redisToken= (HashMap<String, Object>) redisTemplate.boundHashOps(uuid).get("login_item");
                            if (MapUtil.isEmpty(redisToken)){
                                throw new RException("令牌非法");
                            }

                            Boolean flag = (Boolean) redisToken.get("flag");
//        如果登录标志为false,则返回登录失效
                            if (!flag){
                                throw new RException("令牌已作废");
                            }

                            Date expire = (Date) redisToken.get("expire");
                            Long nowTime = new Date().getTime();

                            if (nowTime>=expire.getTime()){
                                throw new RException("令牌过期");
                            }

//                            如果访问期间过期时间小于60分钟，则加时
                            Long exp=expire.getTime()-nowTime;
                            if (exp<=60*60*1000){
                                log.info("还差1小时过期");
                                Date newExp = DateUtils.addDateHours(new Date(), 24); //增加24小时
                                HashMap<String, Object> stringObjectHashMap = new HashMap<>();
                                stringObjectHashMap.put("flag",true);
                                stringObjectHashMap.put("expire",newExp);
                                redisTemplate.boundHashOps(uuid).put("login_item",stringObjectHashMap);
                                redisTemplate.expire(uuid,25, TimeUnit.HOURS);
                            }


                        }
                        log.info("从请求头获取到了token: {}，开始设置请求头",token);
                        //转发令牌到请求头
                        ServerHttpRequest host = request.mutate().header(AUTHORIZE_TOKEN, "Bearer "+ token).build();
                        ServerWebExchange build = exchange.mutate().request(host).build();
//        放行
                        return chain.filter(build);
                    } catch (Exception e) {

                    }
                }
            }
        }




//从请求头获取不到就从cookie中获取
        if (StringUtils.isEmpty(token)){

            HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);
            if (cookie!=null){
               String cookieValue = cookie.getValue();
                token = cookieValue.replace("Bearer ", "");
                log.info("从cookie中获取到了令牌:{}",token);
            }

        }


        //如果cookie不存在令牌,则从请求参数中获取
        if (StringUtils.isEmpty(token)){
           String param = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
           if (StringUtils.isEmpty(param)){
              token= param.replace("Bearer ", "");

           }
        }

//如果token获取不到,抛异常
        if (StringUtils.isEmpty(token)){
            log.info("没有获取到令牌");
            throw new RException("没有权限，请先登录");

        }


        doToken(token); // 判断token 是否生效 是否过期，否则抛异常


//        如果能从cookies获取到token，则添加到头信息
        log.info("开始设置请求头");
        ServerHttpRequest host = request.mutate().header(AUTHORIZE_TOKEN, "Bearer "+ token).build();
        ServerWebExchange build = exchange.mutate().request(host).build();
//        放行
        return chain.filter(build);

    }

    private void doToken(String token) {
        String decode = null;

        try {
           decode = TokenDecode.decode(token);
        } catch (Exception e) {
            log.info("令牌解析失败：{}",e.getMessage());
            throw new RException("令牌失效");

        }

        Map<String,String> tokenMap = JSON.parseObject(decode, Map.class);
        String uuid = tokenMap.get("uuid");
//        log.info("uuid===========>>>>>>>:{}",uuid);

        HashMap<String, Object> redisToken= (HashMap<String, Object>) redisTemplate.boundHashOps(uuid).get("login_item");
        if (MapUtil.isEmpty(redisToken)){
            throw new RException("令牌非法");
        }

        Boolean flag = (Boolean) redisToken.get("flag");
//        如果登录标志为false,则返回登录失效
        if (!flag){
            throw new RException("令牌已作废");
        }
        Date expire = (Date) redisToken.get("expire");
        Long nowTime = new Date().getTime();

        if (nowTime>=expire.getTime()){
            throw new RException("令牌过期了");
        }

        Long exp=expire.getTime()-nowTime;

        if (exp<=60*60*1000){
            log.info("还差1小时过期");
            Date newExp = DateUtils.addDateHours(new Date(), 24); //增加24小时
            HashMap<String, Object> stringObjectHashMap = new HashMap<>();
            stringObjectHashMap.put("flag",true);
            stringObjectHashMap.put("expire",newExp);
            redisTemplate.boundHashOps(uuid).put("login_item",stringObjectHashMap);
            redisTemplate.expire(uuid,25, TimeUnit.HOURS);
        }
    }


    private Boolean isAccess(String url){
        AntPathMatcher pathMatcher = new AntPathMatcher();
        String[] split = accessUrl.split(",");
//        System.out.println(split);
        for (String s : split) {


            if (pathMatcher.match(s,url)){

                return true;
            }
        }
        return false;
    }






    @Override
    public int getOrder() {
        return 0;
    }


}
